package board;

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Vector;

import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;

public class Board {
	
	int fileSize = 10*1024*1024;
	private String uploadPath = "C:\\Users\\jhta\\workspace\\web_1403_2_academy\\WebContent\\upload";
	
	String fileEncoding = "UTF-8";
	
	//------------------------------------------------
	//         JDBC 연결
	//------------------------------------------------
	String driver = "oracle.jdbc.driver.OracleDriver";
	String url = "jdbc:oracle:thin:@127.0.0.10:1521:XE"; 
	String db_user = "hr";
	String db_pwd = "hr";

	Connection conn;
			
	BoardVo vo;


	// 페이지 분리 관련된 필드
	int listSize = 3;  // 한 페이지에 보여질 행수를 설정하는 부분
	int blockSize = 2; // 제일 하단에 표시하는 페이지 번호
	
	int totSize = 0;   // 검색된 데이터 총 갯수
	int totPage = 0;   // 전체 페이지수를 나타낸다.
	int totBlock = 0;
	
	int nowPage = 1;   // 현제 보고 있는 페이지를 나타낸다.
	int nowBlock = 1;  // 현재 블럭을 표시
	
	int startNo = 1;   // 목록의 시작 위치를 표시
	int endNo = 3;     // 목록의 끝 위치를 표시
	
	int startPage = 1; // 현재 블록의 시작 페이지번호
	int endPage = 2;   // 현재 블록의 끝 페이지 번호
	
	
	
	public Board(){
		try {
			// 1) 드라이버 로딩
			Class.forName(driver).newInstance();
			// 2) Connection 객체 생성
			conn = DriverManager.getConnection(url, db_user, db_pwd);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	// *****************************************************************
	//              글 삽입하는 역할
	// *****************************************************************
	public boolean insert() {
		boolean flag = false;
		try {
			MultipartRequest mr = new MultipartRequest(vo.getRequest(), uploadPath, fileSize, fileEncoding,	new DefaultFileRenamePolicy());
			
			String part = mr.getParameter("part");
			String mid = mr.getParameter("mid");
			String subject = mr.getParameter("subject");
			String content = mr.getParameter("content");
			String pwd = mr.getParameter("pwd");

			String orifile = mr.getOriginalFileName("filename");
			String sysfile = mr.getFilesystemName("filename");
			System.out.println(part);
			System.out.println(mid);
			System.out.println(subject);
			System.out.println(content);
			System.out.println(pwd);
			// db저장
			String sql = "insert all"
					+ " into board(serial, part, mid, mdate, subject, pwd, hit, content, grp, deep)"
					+ " values(seq_serial.nextval, ?, ?, sysdate, ?, ?, 0, ?,seq_serial.currval, seq_serial.currval)";
			if (sysfile != null) {
				sql += " into brdfiles(serial, fileid, filename) values(seq_brdfiles.nextval, seq_serial.currval,?)";
			}
			sql += " select * from dual";// 이 셀렉이 문장이있어야 파일이 들어간다.  그리고 쿼리문은 끝까지 확인해줘야 한다.

			try {
				PreparedStatement ps = conn.prepareStatement(sql);
				ps.setString(1, part);
				ps.setString(2, mid);
				ps.setString(3, subject);
				ps.setString(4, pwd);
				ps.setString(5, content);
	
				if (sysfile != null) {
					ps.setString(6, sysfile);
				}

				int cnt = ps.executeUpdate();
				if (cnt > 0) {
					flag = true;
				}
				ps.close();
				conn.close();
				
			} catch (Exception e) {
				e.printStackTrace();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return flag;
	}

	
	
	// *****************************************************************
	//            글 받아오기
	// *****************************************************************
	public BoardVo view(){
		BoardVo v = null;
		String sql = null;
		PreparedStatement ps = null;
		 
		try{
			sql = "update board set hit = (hit + 1) where serial=" + vo.getSerial();
			ps = conn.prepareStatement(sql);
			ps.executeUpdate();
			
			sql = "select b.*, f.* from board b left outer join brdfiles f on b.serial = f.fileid where b.serial=?";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, vo.getSerial());
			
			ResultSet rs = ps.executeQuery();
			
			if(rs.next()){
				v = new BoardVo();
				
				v.setSerial(rs.getInt("serial"));
				v.setMid(rs.getString("mid"));
				v.setPwd(rs.getString("pwd"));
				v.setSubject(rs.getString("subject"));
				v.setContent(rs.getString("content"));
				v.setMdate(rs.getDate("mdate"));
				v.setFilename(rs.getString("filename"));
				v.setGrp(rs.getInt("grp"));
				v.setDeep(rs.getString("deep"));
				v.setHit(rs.getInt("hit"));
				
			}
			rs.close();
			ps.close();
			conn.close();
			
		}catch(Exception ex){
			ex.printStackTrace();
		}
		return v;
	}
	
	
	// *****************************************************************
	//            글 삭제 확인
	// *****************************************************************
	public boolean delete(){
		boolean flag = false;
		
		String sql = "delete from board where serial=?";
		
		try {
			PreparedStatement ps = conn.prepareStatement(sql);
			ps.setInt(1, vo.getSerial());
			
			int cnt = ps.executeUpdate();
			
			if(cnt > 0){
				flag = true;
				
				File file = new File(uploadPath + "/" + vo.getFilename());
				if(file.exists()){
					file.delete();
				}else{
					
				}
			}
			
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return flag;
	}
	
	// *****************************************************************
	//               글 수정 확인
	// *****************************************************************
	public boolean modify(){
		boolean flag = false;
		
		try {			
			MultipartRequest mr = new MultipartRequest(vo.getRequest(), uploadPath, fileSize, fileEncoding, new DefaultFileRenamePolicy());
			// 해당 객체가 생성될때 즉시 파일은 업로드 되고 있다.
			
			String mid     = mr.getParameter("mid");
			String subject = mr.getParameter("subject");
			String content = mr.getParameter("content");
			String pwd     = mr.getParameter("pwd");
			String filename= mr.getParameter("filename");
			
			// sysfile 은 새로운 파일
			String sysfile = mr.getFilesystemName("newfilename");
			int    serial  = Integer.parseInt(mr.getParameter("serial"));
			String fileDelFlag = mr.getParameter("fileDelFlag"); // 삭제할건지 말건지를 확인

			PreparedStatement ps = null;
			String sql = null;
			int cnt = 0;  // 처리된 결과
			
			// 기존 첨부된 파일을 삭제
			if(fileDelFlag.equals("del")){
				fileDel(filename, serial);

			}
			
			// 기본적으로 자동으로 커밋이 되기 때문에, 자동커밋(commit)을 방지하는 기능
			conn.setAutoCommit(false);			
			
			sql = "update board set subject=?, content=? where pwd=? and serial=?";
			System.out.println("4");				
			ps = conn.prepareStatement(sql);
			ps.setString(1, subject);
			ps.setString(2, content);
			ps.setString(3, pwd);
			ps.setInt(4, serial);
			
			cnt = ps.executeUpdate();			
			// 새로운 첨부파일이 존재하지 않으면(내용만 수정)
			
			if(sysfile != null && sysfile != ""){
			
				sql = "insert into brdfiles(serial, fileid, filename) values(seq_brdfiles.nextval, ?, ?)";
				ps = conn.prepareStatement(sql);
				ps.setInt(1, serial);
				ps.setString(2, sysfile);

				cnt = ps.executeUpdate();			
			}
			
			// 삭제를 확인했을 경우 커밋(commit)을 하고 아닌 경우는 롤백해서 Bakc 시킨다.
			if(cnt > 0){
				conn.commit();
				flag = true;
			}else{
				conn.rollback();
			}
			
			ps.close();
			conn.close();
			
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		
		return flag;
	}
	
	public void fileDel(String oldfile, int serial){
		String sql = "delete from brdfiles where fileid=? and filename=?";
		
		try {
			PreparedStatement ps =conn.prepareStatement(sql);
			ps.setInt(1, serial);
			ps.setString(2, oldfile);
			ps.executeUpdate();
			
			File file = new File(uploadPath + "/" + oldfile);
			if(file.exists()) file.delete();
			
			ps.close();
			
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	
	
	
	// *****************************************************************
	//                list 화면에 뿌려줄 함수
	// *****************************************************************
	public Vector<BoardVo> list(){
		
		Vector<BoardVo> v = new Vector<>();
		String sql = "";
		PreparedStatement ps = null;
		ResultSet rs = null;
		
		try {
			// 전체 페이지 수 계산 할 부분
			sql = "select count(serial) cnt from board where (mid like ? or subject like ? or content like ?) and part=?"; // like 뒤에 "and part=?" 넣어줘야한다.
			
			ps = conn.prepareStatement(sql);
			
			ps.setString(1, "%" + vo.getFind() + "%");
			ps.setString(2, "%" + vo.getFind() + "%");
			ps.setString(3, "%" + vo.getFind() + "%");
			ps.setString(4, vo.getPart());
			
			rs = ps.executeQuery();
			rs.next();
			
			totSize = rs.getInt("cnt");
			compute();
			
			
			// part 에 따라서 게시글을 뿌려주기 위해서 mid, subject, content 는 논리적으로 묶어준다.
			sql = "select * from("
						+ "select rownum no, a.* from ("
						+ "select * from board where (mid like ? or subject like ? or content like ?) and part=?" // like?)" 뒤에  and part=?  붙여줘야한다.
						+ "order by grp desc, deep asc)a "
						+ ") where no between ? and ?";
			
			ps = conn.prepareStatement(sql);
			
		
			ps.setString(1, "%" + vo.getFind() + "%");
			ps.setString(2, "%" + vo.getFind() + "%");
			ps.setString(3, "%" + vo.getFind() + "%");
			ps.setString(4, vo.getPart());
			ps.setInt(5, startNo);
			ps.setInt(6, endNo);
			
			rs = ps.executeQuery();
			
			while(rs.next()){
				BoardVo vo = new BoardVo();
				
				vo.setSerial(rs.getInt("serial"));
				vo.setMid(rs.getString("mid"));
				vo.setSubject(rs.getString("subject"));
				vo.setContent(rs.getString("content"));
				vo.setMdate(rs.getDate("mdate"));
				vo.setHit(rs.getInt("hit"));

				v.add(vo);
			}
			
			rs.close();
			ps.close();
			conn.close();
			
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return v;
	}
	
	// 페이지 수, 블록 수 등을 계산하기 위해서
	public void compute(){
		// ceil은 반환타입이 long type 이라서 정수형으로 바꿔주고 1.0을 곱해야 한다.
		// 전체 페이지 수 계산
		totPage = (int)Math.ceil(totSize*1.0 / listSize);
		// 총 블록 수 계산
		totBlock = (int)Math.ceil(totPage*1.0 / blockSize);
		// 현재 블록을 표시
		nowBlock = (int)Math.ceil(nowPage*1.0 / blockSize);
		
		// 가장 끝 페이지를 표시하는데 가장 끝 페이지가 전체 페이지수를 넘어버릴 수 있기 때문에 예외처리한다.
		endPage = nowBlock * blockSize;
		startPage = endPage - blockSize + 1;
		if(totPage < endPage) endPage = totPage;
		
		endNo = nowPage * listSize;
		startNo = endNo - listSize + 1;
		if(totSize < endNo) endNo = totSize;
	}
	

	// *****************************************************************
	//                답글 달기
	// *****************************************************************
	public boolean repInsert(){
		boolean flag = false;
		
		try {
			MultipartRequest mr = new MultipartRequest(vo.getRequest(), uploadPath, fileSize, fileEncoding,	new DefaultFileRenamePolicy());
			
			String part = mr.getParameter("part");
			String mid = mr.getParameter("mid");
			String subject = mr.getParameter("subject");
			String content = mr.getParameter("content");
			String pwd = mr.getParameter("pwd");

			String orifile = mr.getOriginalFileName("filename");
			String sysfile = mr.getFilesystemName("filename");

			int grp = Integer.parseInt(mr.getParameter("grp"));
			String deep = mr.getParameter("deep");
			
			// db저장
			String sql = "insert all"
					+ " into board(serial, part, mid, mdate, subject, pwd, hit, content, grp, deep)"
					+ " values(seq_serial.nextval, ?, ?, sysdate, ?, ?, 0, ?, ?, ? || seq_serial.currval)";
			if (sysfile != null) {
				sql += " into brdfiles(serial, fileid, filename) values(seq_brdfiles.nextval, seq_serial.currval, ?)";
			}
			
			sql += " select * from dual";// 이 셀렉이 문장이있어야 파일이 들어간다.  그리고 쿼리문은 끝까지 확인해줘야 한다.

			try {
				PreparedStatement ps = conn.prepareStatement(sql);
				ps.setString(1, part);
				ps.setString(2, mid);
				ps.setString(3, subject);
				ps.setString(4, pwd);
				ps.setString(5, content);
				ps.setInt(6, grp);
				ps.setString(7, deep + "-");
				
				if (sysfile != null) { ps.setString(8, sysfile); }

				int cnt = ps.executeUpdate();
				if (cnt > 0) { flag = true; }
				
				ps.close();
				conn.close();
				
			} catch (Exception e) {
				e.printStackTrace();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return flag;
	}
	
	public BoardVo getVo() {
		return vo;
	}

	public void setVo(BoardVo vo) {
		this.vo = vo;
	}
	
	public String getUploadPath() {
		return uploadPath;
	}
	
	// 페이지 분리와 관련된 메서드
	
	public int getListSize() {
		return listSize;
	}

	public void setListSize(int listSize) {
		this.listSize = listSize;
	}

	public int getBlockSize() {
		return blockSize;
	}

	public void setBlockSize(int blockSize) {
		this.blockSize = blockSize;
	}

	public int getTotSize() {
		return totSize;
	}

	public void setTotSize(int totSize) {
		this.totSize = totSize;
	}

	public int getTotPage() {
		return totPage;
	}

	public void setTotPage(int totPage) {
		this.totPage = totPage;
	}

	public int getNowPage() {
		return nowPage;
	}

	public void setNowPage(int nowPage) {
		this.nowPage = nowPage;
	}

	public int getNowBlock() {
		return nowBlock;
	}

	public void setNowBlock(int nowBlock) {
		this.nowBlock = nowBlock;
	}

	public int getStartNo() {
		return startNo;
	}

	public void setStartNo(int startNo) {
		this.startNo = startNo;
	}

	public int getEndNo() {
		return endNo;
	}

	public void setEndNo(int endNo) {
		this.endNo = endNo;
	}

	public int getStartPage() {
		return startPage;
	}

	public void setStartPage(int startPage) {
		this.startPage = startPage;
	}

	public int getEndPage() {
		return endPage;
	}

	public void setEndPage(int endPage) {
		this.endPage = endPage;
	}
	
	public int getTotBlock() {
		return totBlock;
	}

	public void setTotBlock(int totBlock) {
		this.totBlock = totBlock;
	}

	
}
